package com.faiz.ugla.griplog;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.AsyncTask;
import android.os.CountDownTimer;
import android.os.IBinder;
import android.os.SystemClock;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.util.Log;

public class LoggingService extends Service implements SensorEventListener {

	//Shared preferences vars
	private SharedPreferences appSettings;

	//Hardware sensor vars
	private SensorManager sensorManager;
	private Sensor proxSensor;
	private float distance;

	//Plotting vars
	private Intent plotIntent;

	//SK7 vars
	private SK7Sample sk7Sample;

	//FakeCall vars
	private boolean callInitiated;
	private boolean callAnswered;
	private FakeCallReceiver fakeCallReceiver;
	private IntentFilter fakeCallIntentFilter;
	protected static final String FAKE_CALL_INIT_ACTION = "FakeCallAction";
	protected static final String FAKE_CALL_ANSWER_ACTION = "FakeCallAnswerAction";
	private int ansEvent;

	//Debugging vars
	private static final String DEBUG_TAG = "LoggingService";

	//Distance timer
	private DistanceTimer dTimer;
	private boolean dTimerHasStarted;

	//DataWriter vars
	private volatile DataWriter dataWriter;

	//Participant and task vars
	private String currentParticipant;
	private int currentTask;

	@Override
	public void onCreate() {
		//Register sensorManager
		sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

		//Get proximity sensor
		proxSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);

		//Set distance to 1 (far proximity)
		distance = 1;

		//Set callInitiated and callAnswered
		callInitiated = false;
		callAnswered = false;

		//FakeCallReceiver
		fakeCallReceiver = new FakeCallReceiver();
		fakeCallIntentFilter = new IntentFilter();
		fakeCallIntentFilter.addAction(FAKE_CALL_INIT_ACTION);
		fakeCallIntentFilter.addAction(FAKE_CALL_ANSWER_ACTION);

		//Default flag
		dTimerHasStarted = false;

		//Get values from SharedPreference
		PreferenceManager.setDefaultValues(this, R.xml.prefs, false);
		appSettings = PreferenceManager.getDefaultSharedPreferences(this);

		//Create a DataWriter
		dataWriter = new DataWriter();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		super.onStartCommand(intent, flags, startId);

		//Register sensor
		sensorManager.registerListener(this, proxSensor, SensorManager.SENSOR_DELAY_UI);

		//Execute SK7 thread
		sk7Sample = new SK7Sample();
		sk7Sample.execute();

		//Create plot intent
		plotIntent = new Intent();

		//Register broadcast receiver
		registerReceiver(fakeCallReceiver, fakeCallIntentFilter);

		Log.d(DEBUG_TAG, "LoggingService started");

		return START_STICKY;
	}

	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void onDestroy() {
		super.onDestroy();

		Log.d(DEBUG_TAG,"onDestroy() was called!");

		//Stop SK7Sample thread
		sk7Sample.cancel(true);

		//Unregister fakeCallReceiver
		if (fakeCallReceiver != null) {
			unregisterReceiver(fakeCallReceiver);
		}

		if(sensorManager != null) {
			sensorManager.unregisterListener(this);
			Log.d(DEBUG_TAG, "Sensor listener unregistered");
		}

		//Stop service
		stopSelf();
	}

	private class SK7Sample extends AsyncTask<Void,Void,Void> {
		//Debugging tag
		private static final String DEBUG_TAG = "SK7Sample";

		private int[] acc;
		private int[] cap1 = null;
		private int[] cap2 = null;
		private int[] gyro;

		//Timestamp vars
		private long cTime;

		@Override
		protected void onPreExecute() {
			currentParticipant = appSettings.getString("CONFIG_PARTICIPANT_INFO_KEY", "1");
			dataWriter.createDir(currentParticipant);
		}

		@Override
		protected Void doInBackground(Void... params) {
			final long sTime = SystemClock.elapsedRealtime();

			if (GripLog.connected) {
				while(GripLog.connected) {
					try {
						//Android time stamp
						cTime =  SystemClock.elapsedRealtime() - sTime;

						//Acquire samples from accelerometer
						acc = GripLog.sk7.acc();

						//Acquire samples from extCS3 block 2
						cap2 = GripLog.sk7.sk7_cap_ext(1);

						//Acquire samples from extCS3 block 1
						cap1 = GripLog.sk7.sk7_cap_ext(0);

						//Acquire samples from gyrometer
						gyro = GripLog.sk7.gyro();

						//Combine both capacitive blocks
						int[] cap = {cap1[11], cap1[10], cap1[9], cap1[8], cap1[7], cap1[6], cap1[5], cap1[4], cap1[3], cap1[2], cap1[1], cap1[0], cap2[11], cap2[10], cap2[9], cap2[8], cap2[7], cap2[6], cap2[5], cap2[4], cap2[3], cap2[2], cap2[1], cap2[0]};

						//Debugging 
						//Log.d("START_TIMESTAMP", "Start time: " + sTime);
						//Log.d("CAP", "t: " + cTime + "X: " + cap[0] + " W: " + cap[1] + " V: " + cap[2] + " U: " + cap[3] + " T: " + cap[4] + " S: " + cap[5] + " R: " + cap[6] + " Q: " + cap[7] + " P: " +  cap[8] + " O: " + cap[9] + " N: " + cap[10] + " M: " + cap[11] + " L: " + cap[12] + " K: " + cap[13] + " J: " + cap[14] + " I: " + cap[15] + " H: " + cap[16] + " G: " + cap[17] + " F: " + cap[18] + " E: " + cap[19] + " D: " + cap[20] + " C: " + cap[21] + " B: " + cap[22] + " A: " + cap[23]);
						//Log.d("ACC", "t: " + cTime + " X: " + acc[0] + " Y: " + acc[1] + " Z: " + acc[2]);
						//Log.d("GYRO", "t: " + cTime + " Pitch: " + gyro[0] + " Roll: " + gyro[1] + " Yaw: " + gyro[2]);

						if (!callAnswered)
							ansEvent = 1;
						else
							ansEvent = 2;

						if(callInitiated) {
							Log.d(DEBUG_TAG, "ansEvent = " + ansEvent);
							dataWriter.writeData(cTime, ansEvent, acc, gyro, cap);
						}


						plotIntent.setAction(GripLog.PLOT_INTENT_ACTION);
						plotIntent.putExtra("Acc", acc);
						plotIntent.putExtra("Cap", cap);
						sendBroadcast(plotIntent);

						Thread.sleep(5);

					} catch(InterruptedException ie) {
						Log.e(DEBUG_TAG, "Something went wrong with the SK7 sampling thread!!");
					}
				}				
			}
			return null;
		}
	}

	private class DistanceTimer extends CountDownTimer {
		//Debugging tag
		private static final String DEBUG_TAG = "DistanceTimer";

		public DistanceTimer(long millisInFuture, long countDownInterval) {
			super(millisInFuture, countDownInterval);
			Log.d(DEBUG_TAG, "Distance timer created");
		}

		@Override
		public void onTick(long millisUntilFinished) {
			Log.d(DEBUG_TAG, ": Seconds remaining: " + millisUntilFinished / 1000);
		}

		@Override
		public void onFinish() {
			//Reset flags
			callInitiated = false;
			callAnswered = false;

			//Stop writing and close the file
			dataWriter.closeFile();

			//Set distance to far
			distance = 1;

			Vibrator vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
			vib.vibrate(2000);

			//Reset flag
			dTimerHasStarted = false;
		}
	}

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		// TODO Auto-generated method stub
	}

	@Override
	public void onSensorChanged(SensorEvent event) {
		distance = event.values[0];
		Log.d(DEBUG_TAG, "Distance = " + distance);

		if(distance == 0 && callAnswered) {
			if(!dTimerHasStarted) {
				dTimer = new DistanceTimer(3000,1000);
				dTimer.start();
				Log.d(DEBUG_TAG, "Timer started");
				dTimerHasStarted = true;
			}
		}

		if(distance == 1 && dTimerHasStarted) {
			dTimer.cancel();
			Log.d(DEBUG_TAG, "Timer canceled");
			dTimerHasStarted = false;
		}
	}

	private class FakeCallReceiver extends BroadcastReceiver {
		//Debugging tag
		private static final String DEBUG_TAG = "FakeCallReceiver";

		@Override
		public void onReceive(Context arg0, Intent intent) {

			String intentAction = intent.getAction();

			if (intentAction.equals(FAKE_CALL_INIT_ACTION)) {
				callInitiated = intent.getBooleanExtra("Initiated", false);
				currentTask = intent.getIntExtra("Task", 1);

				if (callInitiated) {
					dataWriter.createFile(String.valueOf(currentTask));
				}

				Log.d(DEBUG_TAG, "callInitiated = " + callInitiated);

			} else
				if(intentAction.equals(FAKE_CALL_ANSWER_ACTION)) {
					callAnswered = intent.getBooleanExtra("Answered", false);
					Log.d(DEBUG_TAG, "callAnswered = " + callAnswered);
				} 
		}
	}
}
